/*******************************************************************************
 * Copyright (c) 2000, 2004 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.widgets.shell;


private import dwt.dwt;

private import dwt.events.events;
private import dwt.events.listeners;
private import dwt.graphics.cursor;
private import dwt.graphics.image;
private import dwt.graphics.point;
private import dwt.graphics.rectangle;
private import dwt.graphics.region;
private import dwt.internal.win32.os;
private import dwt.util.eventhandler;
private import dwt.util.util;
private import dwt.widgets.display;
private import dwt.widgets.menu;
private import dwt.widgets.typedlistener;

public import dwt.widgets.decorations;


/**
 * Instances of this class represent the "windows"
 * which the desktop or "window manager" is managing.
 * Instances that do not have a parent (that is, they
 * are built using the constructor, which takes a 
 * <code>Display</code> as the argument) are described
 * as <em>top level</em> shells. Instances that do have
 * a parent are described as <em>secondary</em> or
 * <em>dialog</em> shells.
 * <p>
 * Instances are always displayed in one of the maximized, 
 * minimized or normal states:
 * <ul>
 * <li>
 * When an instance is marked as <em>maximized</em>, the
 * window manager will typically resize it to fill the
 * entire visible area of the display, and the instance
 * is usually put in a state where it can not be resized 
 * (even if it has style <code>RESIZE</code>) until it is
 * no longer maximized.
 * </li><li>
 * When an instance is in the <em>normal</em> state (neither
 * maximized or minimized), its appearance is controlled by
 * the style constants which were specified when it was created
 * and the restrictions of the window manager (see below).
 * </li><li>
 * When an instance has been marked as <em>minimized</em>,
 * its contents (client area) will usually not be visible,
 * and depending on the window manager, it may be
 * "iconified" (that is, replaced on the desktop by a small
 * simplified representation of itself), relocated to a
 * distinguished area of the screen, or hidden. Combinations
 * of these changes are also possible.
 * </li>
 * </ul>
 * </p>
 * <p>
 * Note: The styles supported by this class must be treated
 * as <em>HINT</em>s, since the window manager for the
 * desktop on which the instance is visible has ultimate
 * control over the appearance and behavior of decorations
 * and modality. For example, some window managers only
 * support resizable windows and will always assume the
 * RESIZE style, even if it is not set. In addition, if a
 * modality style is not supported, it is "upgraded" to a
 * more restrictive modality style that is supported. For
 * example, if <code>PRIMARY_MODAL</code> is not supported,
 * it would be upgraded to <code>APPLICATION_MODAL</code>.
 * <dl>
 * <dt><b>Styles:</b></dt>
 * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE</dd>
 * <dd>APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL</dd>
 * <dt><b>Events:</b></dt>
 * <dd>Activate, Close, Deactivate, Deiconify, Iconify</dd>
 * </dl>
 * Class <code>DWT</code> provides two "convenience constants"
 * for the most commonly required style combinations:
 * <dl>
 * <dt><code>SHELL_TRIM</code></dt>
 * <dd>
 * the result of combining the constants which are required
 * to produce a typical application top level shell: (that 
 * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>)
 * </dd>
 * <dt><code>DIALOG_TRIM</code></dt>
 * <dd>
 * the result of combining the constants which are required
 * to produce a typical application dialog shell: (that 
 * is, <code>TITLE | CLOSE | BORDER</code>)
 * </dd>
 * </dl>
 * </p>
 * <p>
 * Note: Only one of the styles APPLICATION_MODAL, MODELESS, 
 * PRIMARY_MODAL and SYSTEM_MODAL may be specified.
 * </p><p>
 * IMPORTANT: This class is not intended to be subclassed.
 * </p>
 *
 * @see Decorations
 * @see DWT
 */
public class Shell : Decorations {
	
	Menu activeMenu;
	HIMC hIMC;
	HWND hwndMDIClient_var, toolTipHandle;
	
	int minWidth = DWT.DEFAULT, minHeight = DWT.DEFAULT;
	
	HBRUSH [] brushes;
	boolean showWithParent;
	Control lastActive;

	Region region;
	static WNDPROC_I DialogProc;
	version(WinCE){
		SHACTIVATEINFO* psai;
		static const char[] DialogClass = "Dialog";
	}else{
		static const char[] DialogClass = "#32770";
	}
	
	
	private static boolean staticCtor_done = false;
	static void staticCtor() {
		if(staticCtor_done) return;
		staticCtor_done = true;
		WNDCLASS_T lpWndClass;
		OS.GetClassInfo (null, Converter.StrToTCHARz(DialogClass), &lpWndClass);
		DialogProc = lpWndClass.lpfnWndProc;
	}

/**
 * Constructs a new instance of this class. This is equivalent
 * to calling <code>Shell((Display) null)</code>.
 *
 * @exception SWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
 *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
 * </ul>
 */
public this () {
	this (cast(Display) null);
}

/**
 * Constructs a new instance of this class given only the style
 * value describing its behavior and appearance. This is equivalent
 * to calling <code>Shell((Display) null, style)</code>.
 * <p>
 * The style value is either one of the style constants defined in
 * class <code>DWT</code> which is applicable to instances of this
 * class, or must be built by <em>bitwise OR</em>'ing together 
 * (that is, using the <code>int</code> "|" operator) two or more
 * of those <code>DWT</code> style constants. The class description
 * lists the style constants that are applicable to the class.
 * Style bits are also inherited from superclasses.
 * </p>
 *
 * @param style the style of control to construct
 *
 * @exception SWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
 *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
 * </ul>
 * 
 * @see DWT#BORDER
 * @see DWT#CLOSE
 * @see DWT#MIN
 * @see DWT#MAX
 * @see DWT#RESIZE
 * @see DWT#TITLE
 * @see DWT#NO_TRIM
 * @see DWT#SHELL_TRIM
 * @see DWT#DIALOG_TRIM
 * @see DWT#MODELESS
 * @see DWT#PRIMARY_MODAL
 * @see DWT#APPLICATION_MODAL
 * @see DWT#SYSTEM_MODAL
 */
public this (int style) {
	this (cast(Display) null, style);
}

/**
 * Constructs a new instance of this class given only the display
 * to create it on. It is created with style <code>DWT.SHELL_TRIM</code>.
 * <p>
 * Note: Currently, null can be passed in for the display argument.
 * This has the effect of creating the shell on the currently active
 * display if there is one. If there is no current display, the 
 * shell is created on a "default" display. <b>Passing in null as
 * the display argument is not considered to be good coding style,
 * and may not be supported in a future release of DWT.</b>
 * </p>
 *
 * @param display the display to create the shell on
 *
 * @exception SWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
 *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
 * </ul>
 */
public this (Display display) {
	version(WinCE)
	{
	this (display, DWT.NONE);
	}
	else
	{
	this (display, DWT.SHELL_TRIM);
	}
}

/**
 * Constructs a new instance of this class given the display
 * to create it on and a style value describing its behavior
 * and appearance.
 * <p>
 * The style value is either one of the style constants defined in
 * class <code>DWT</code> which is applicable to instances of this
 * class, or must be built by <em>bitwise OR</em>'ing together 
 * (that is, using the <code>int</code> "|" operator) two or more
 * of those <code>DWT</code> style constants. The class description
 * lists the style constants that are applicable to the class.
 * Style bits are also inherited from superclasses.
 * </p><p>
 * Note: Currently, null can be passed in for the display argument.
 * This has the effect of creating the shell on the currently active
 * display if there is one. If there is no current display, the 
 * shell is created on a "default" display. <b>Passing in null as
 * the display argument is not considered to be good coding style,
 * and may not be supported in a future release of DWT.</b>
 * </p>
 *
 * @param display the display to create the shell on
 * @param style the style of control to construct
 *
 * @exception SWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
 *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
 * </ul>
 * 
 * @see DWT#BORDER
 * @see DWT#CLOSE
 * @see DWT#MIN
 * @see DWT#MAX
 * @see DWT#RESIZE
 * @see DWT#TITLE
 * @see DWT#NO_TRIM
 * @see DWT#SHELL_TRIM
 * @see DWT#DIALOG_TRIM
 * @see DWT#MODELESS
 * @see DWT#PRIMARY_MODAL
 * @see DWT#APPLICATION_MODAL
 * @see DWT#SYSTEM_MODAL
 */
public this (Display display, int style) {
	this (display, null, style, null);
}

this (Display display, Shell parent, int style, HWND handle) {
	staticCtor();
	
	super ();
	checkSubclass ();
	if (display is null) display = Display.getCurrent ();
	if (display is null) display = Display.getDefault ();
	if (!display.isValidThread ()) {
		error(__FILE__, __LINE__, DWT.ERROR_THREAD_INVALID_ACCESS);
	}
	this.style = checkStyle (style);
	this.parent = parent;
	this.display = display;
	this.handle = handle;
	createWidget ();
}

/**
 * Constructs a new instance of this class given only its
 * parent. It is created with style <code>DWT.DIALOG_TRIM</code>.
 * <p>
 * Note: Currently, null can be passed in for the parent.
 * This has the effect of creating the shell on the currently active
 * display if there is one. If there is no current display, the 
 * shell is created on a "default" display. <b>Passing in null as
 * the parent is not considered to be good coding style,
 * and may not be supported in a future release of DWT.</b>
 * </p>
 *
 * @param parent a shell which will be the parent of the new instance
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
 * </ul>
 * @exception SWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
 *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
 * </ul>
 */
public this (Shell parent) {
	version(WinCE)
	{
	this (parent, DWT.NONE);
	}
	else
	{
	this (parent, DWT.DIALOG_TRIM);
	}	
}

/**
 * Constructs a new instance of this class given its parent
 * and a style value describing its behavior and appearance.
 * <p>
 * The style value is either one of the style constants defined in
 * class <code>DWT</code> which is applicable to instances of this
 * class, or must be built by <em>bitwise OR</em>'ing together 
 * (that is, using the <code>int</code> "|" operator) two or more
 * of those <code>DWT</code> style constants. The class description
 * lists the style constants that are applicable to the class.
 * Style bits are also inherited from superclasses.
 * </p><p>
 * Note: Currently, null can be passed in for the parent.
 * This has the effect of creating the shell on the currently active
 * display if there is one. If there is no current display, the 
 * shell is created on a "default" display. <b>Passing in null as
 * the parent is not considered to be good coding style,
 * and may not be supported in a future release of DWT.</b>
 * </p>
 *
 * @param parent a shell which will be the parent of the new instance
 * @param style the style of control to construct
 *
 * @exception SWTException <ul>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
 *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
 * </ul>
 * 
 * @see DWT#BORDER
 * @see DWT#CLOSE
 * @see DWT#MIN
 * @see DWT#MAX
 * @see DWT#RESIZE
 * @see DWT#TITLE
 * @see DWT#NO_TRIM
 * @see DWT#SHELL_TRIM
 * @see DWT#DIALOG_TRIM
 * @see DWT#MODELESS
 * @see DWT#PRIMARY_MODAL
 * @see DWT#APPLICATION_MODAL
 * @see DWT#SYSTEM_MODAL
 */
public this (Shell parent, int style) {
	this (parent !is null ? parent.display : null, parent, style, null);
}

/**	 
 * Invokes platform specific functionality to allocate a new shell.
 * <p>
 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
 * API for <code>Shell</code>. It is marked public only so that it
 * can be shared within the packages provided by DWT. It is not
 * available on all platforms, and should never be called from
 * application code.
 * </p>
 *
 * @param display the display for the shell
 * @param handle the handle for the shell
 * @return a new shell object containing the specified display and handle
 */
public static Shell win32_new (Display display, HWND handle) {
	staticCtor();
	
	return new Shell (display, null, DWT.NO_TRIM, handle);
}

static int checkStyle (int style) {
	style = Decorations.checkStyle (style);
	int mask = DWT.SYSTEM_MODAL | DWT.APPLICATION_MODAL | DWT.PRIMARY_MODAL;
	int bits = style & ~mask;
	if ((style & DWT.SYSTEM_MODAL) != 0) return bits | DWT.SYSTEM_MODAL;
	if ((style & DWT.APPLICATION_MODAL) != 0) return bits | DWT.APPLICATION_MODAL;
	if ((style & DWT.PRIMARY_MODAL) != 0) return bits | DWT.PRIMARY_MODAL;
	return bits;
}

/**
 * Adds the listener to the collection of listeners who will
 * be notified when operations are performed on the receiver,
 * by sending the listener one of the messages defined in the
 * <code>ShellListener</code> interface.
 *
 * @param listener the listener which should be notified
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
 * </ul>
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see ShellListener
 * @see #removeShellListener
 */
public void addShellListener (ShellListener listener) {
	checkWidget ();
	if (listener is null) error(__FILE__, __LINE__, DWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (DWT.Close,typedListener);
	addListener (DWT.Iconify,typedListener);
	addListener (DWT.Deiconify,typedListener);
	addListener (DWT.Activate, typedListener);
	addListener (DWT.Deactivate, typedListener);
}

LRESULT callWindowProc (int msg, int wParam, int lParam) {
	if (parent !is null) {
		if (handle is null) return 0;
		switch (msg) {
			case OS.WM_KILLFOCUS:
			case OS.WM_SETFOCUS: 
				return OS.DefWindowProc (handle, msg, wParam, lParam);
			default : break;
		}
		return OS.CallWindowProc (DialogProc, handle, msg, wParam, lParam);
	}
	if (handle is null) return 0;
	if (hwndMDIClient_var !is null) {
		return OS.DefFrameProc (handle, hwndMDIClient_var, msg, wParam, lParam);
	}
	return OS.DefWindowProc (handle, msg, wParam, lParam);
}

/**
 * Requests that the window manager close the receiver in
 * the same way it would be closed when the user clicks on
 * the "close box" or performs some other platform specific
 * key or mouse combination that indicates the window
 * should be removed.
 *
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see DWT#Close
 * @see #dispose
 */
public void close () {
	checkWidget ();
	OS.PostMessage (handle, OS.WM_CLOSE, 0, 0);
}

void createHandle () {
	boolean embedded = (handle !is null);
	
	/*
	* On Windows 98 and NT, setting a window to be the
	* top most window using HWND_TOPMOST can result in a
	* parent dialog shell being moved behind its parent
	* if the dialog has a sibling that is currently on top
	* This only occurs using SetWindowPos (), not when the
	* handle is created.
	*/
	/*
	* The following code is intentionally commented.
	*/
//	if ((style & DWT.ON_TOP) != 0) display.lockActiveWindow = true;
	super.createHandle ();
	
	/*
	* The following code is intentionally commented.
	*/
//	if ((style & DWT.ON_TOP) != 0)  display.lockActiveWindow = false;
	
	if (!embedded) {
		int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);	
		bits &= ~(OS.WS_OVERLAPPED | OS.WS_CAPTION);
		version(WinCE) {} else {  bits |= OS.WS_POPUP; }
		if ((style & DWT.TITLE) != 0) bits |= OS.WS_CAPTION;
		if ((style & DWT.NO_TRIM) == 0) {
			if ((style & (DWT.BORDER | DWT.RESIZE)) == 0) bits |= OS.WS_BORDER;
		}
		/*
		* Bug in Windows.  When the WS_CAPTION bits are cleared using
		* SetWindowLong(), Windows does not resize the client area of
		* the window to get rid of the caption until the first resize.
		* The fix is to use SetWindowPos() with SWP_DRAWFRAME to force
		* the frame to be redrawn and resized.
		*/
		OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
		int flags = OS.SWP_DRAWFRAME | OS.SWP_NOMOVE | OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE;
		SetWindowPos (handle, null, 0, 0, 0, 0, flags);
		version(WinCE) { 
		setMaximized (true); 
		if (OS.IsPPC) {
			psai = new SHACTIVATEINFO ();
			psai.cbSize = SHACTIVATEINFO.sizeof;
		}
		}
	}
	if (OS.IsDBLocale) {
		hIMC = OS.ImmCreateContext ();
		if (hIMC !is null) OS.ImmAssociateContext (handle, hIMC);
	}
}

public void dispose () {
	/*
	* This code is intentionally commented.  On some
	* platforms, the owner window is repainted right
	* away when a dialog window exits.  This behavior
	* is currently unspecified.
	*/
//	/*
//	* Note:  It is valid to attempt to dispose a widget
//	* more than once.  If this happens, fail silently.
//	*/
//	if (!isValidWidget ()) return;
//	if (!isValidThread ()) error (DWT.ERROR_THREAD_INVALID_ACCESS);
//	Display oldDisplay = display;
	super.dispose ();
	// widget is disposed at this point
//	if (oldDisplay !is null) oldDisplay.update ();
}

void enableWidget (boolean enabled) {
	if (enabled) {
		state &= ~DISABLED;
	} else {
		state |= DISABLED;
	}
	if (Display.TrimEnabled) {
		if (isActive ()) setItemEnabled (OS.SC_CLOSE, enabled);
	} else {
		OS.EnableWindow (handle, enabled);
	}
}

HBRUSH findBrush (int pixel) {
	if (pixel == OS.GetSysColor (OS.COLOR_BTNFACE)) {
		return OS.GetSysColorBrush (OS.COLOR_BTNFACE);
	}
	if (pixel == OS.GetSysColor (OS.COLOR_WINDOW)) {
		return OS.GetSysColorBrush (OS.COLOR_WINDOW);
	}
	if (brushes is null) brushes = new HBRUSH [4];
	LOGBRUSH* logBrush = new LOGBRUSH ();
	for (int i=0; i<brushes.length; i++) {
		HBRUSH hBrush = brushes [i];
		if (hBrush is null) break;
		OS.GetObject (hBrush, LOGBRUSH.sizeof, logBrush);
		if (logBrush.lbColor == pixel) return hBrush;
	}
	int len = brushes.length;
	HBRUSH hBrush = brushes [--len];
	if (hBrush !is null) OS.DeleteObject (hBrush);
	System.arraycopy (cast(int[])brushes, 0, cast(int[])brushes, 1, len);
	brushes [0] = hBrush = OS.CreateSolidBrush (pixel);
	return hBrush;
}

Cursor findCursor () {
	return cursor;
}

void fixShell (Shell newShell, Control control) {
	if (this is newShell) return;
	if (control is lastActive) setActiveControl (null);
	if (toolTipHandle !is null) {
		setToolTipText (control.handle, null);
	}
	newShell.setToolTipText (control.handle, control.toolTipText_var);
}

/**
 * Moves the receiver to the top of the drawing order for
 * the display on which it was created (so that all other
 * shells on that display, which are not the receiver's
 * children will be drawn behind it) and forces the window
 * manager to make the shell active.
 *
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @since 2.0
 * @see Control#moveAbove
 * @see Control#setFocus
 * @see Control#setVisible
 * @see Display#getActiveShell
 * @see Decorations#setDefaultButton
 * @see Shell#open
 * @see Shell#setActive
 */
public void forceActive () {
	checkWidget ();
	OS.SetForegroundWindow (handle);
}

void forceResize () {
	/* Do nothing */
}

public Rectangle getBounds () {
	checkWidget ();
	version(WinCE) { } else {
		if (OS.IsIconic (handle)) return super.getBounds ();
	}
	RECT rect;
	OS.GetWindowRect (handle, &rect);
	int width = rect.right - rect.left;
	int height = rect.bottom - rect.top;
	return new Rectangle (rect.left, rect.top, width, height);
}

public boolean getEnabled () {
	checkWidget ();
	return (state & DISABLED) == 0;
}

/**
 * Returns the receiver's input method editor mode. This
 * will be the result of bitwise OR'ing together one or
 * more of the following constants defined in class
 * <code>DWT</code>:
 * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>, 
 * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>.
 *
 * @return the IME mode
 *
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see DWT
 */
public int getImeInputMode () {
	checkWidget ();
	if (!OS.IsDBLocale) return 0;
	HIMC hIMC = OS.ImmGetContext (handle);
	DWORD lpfdwConversion;
	DWORD lpfdwSentence;
	int open = OS.ImmGetOpenStatus (hIMC);
	if (open) open = OS.ImmGetConversionStatus (hIMC, &lpfdwConversion, &lpfdwSentence);
	OS.ImmReleaseContext (handle, hIMC);
	if (!open) return DWT.NONE;
	int result = 0;
	if ((lpfdwConversion & OS.IME_CMODE_ROMAN) != 0) result |= DWT.ROMAN;
	if ((lpfdwConversion & OS.IME_CMODE_FULLSHAPE) != 0) result |= DWT.DBCS;
	if ((lpfdwConversion & OS.IME_CMODE_KATAKANA) != 0) return result | DWT.PHONETIC;
	if ((lpfdwConversion & OS.IME_CMODE_NATIVE) != 0) return result | DWT.NATIVE;
	return result | DWT.ALPHA;
}

public Point getLocation () {
	checkWidget ();
	version(WinCE) { } else {
		if (OS.IsIconic (handle)) {
			return super.getLocation ();
		}
	}
	RECT rect;
	OS.GetWindowRect (handle, &rect);
	return new Point (rect.left, rect.top);
}

/** 
 * Returns the region that defines the shape of the shell,
 * or null if the shell has the default shape.
 *
 * @return the region that defines the shape of the shell (or null)
 *	
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @since 3.0
 *
 */
public Region getRegion () {
	checkWidget ();
	return region;
}

public Shell getShell () {
	checkWidget ();
	return this;
}

public Point getSize () {
	checkWidget ();
	version(WinCE) { } else {
		if (OS.IsIconic (handle)) return super.getSize ();
	}
	RECT rect;
	OS.GetWindowRect (handle, &rect);
	int width = rect.right - rect.left;
	int height = rect.bottom - rect.top;
	return new Point (width, height);
}

/**
 * Returns an array containing all shells which are 
 * descendents of the receiver.
 * <p>
 * @return the dialog shells
 *
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 */
public Shell [] getShells () {
	checkWidget ();
	int count = 0;
	Shell [] shells = display.getShells ();
	for (int i=0; i<shells.length; i++) {
		Control shell = shells [i];
		do {
			shell = shell.parent;
		} while (shell !is null && shell !is this);
		if (shell is this) count++;
	}
	int index = 0;
	Shell [] result = new Shell [count];
	for (int i=0; i<shells.length; i++) {
		Control shell = shells [i];
		do {
			shell = shell.parent;
		} while (shell !is null && shell !is this);
		if (shell is this) {
			result [index++] = shells [i];
		}
	}
	return result;
}

public boolean isEnabled () {
	checkWidget ();
	return getEnabled ();
}

public boolean isVisible () {
	checkWidget ();
	return getVisible ();
}

HWND hwndMDIClient () {
	if (hwndMDIClient_var is null) {
		int widgetStyle = OS.MDIS_ALLCHILDSTYLES | OS.WS_CHILD | OS.WS_CLIPCHILDREN | OS.WS_CLIPSIBLINGS;
		hwndMDIClient_var = OS.CreateWindowEx (
			0,
			Converter.StrToTCHARz(("MDICLIENT")),
			null,
			widgetStyle, 
			0, 0, 0, 0,
			handle,
			null,
			OS.GetModuleHandle (null),
			new CREATESTRUCT ());
//		OS.ShowWindow (hwndMDIClient, OS.SW_SHOW);
	}
	return hwndMDIClient_var;
}

/**
 * Moves the receiver to the top of the drawing order for
 * the display on which it was created (so that all other
 * shells on that display, which are not the receiver's
 * children will be drawn behind it), marks it visible,
 * sets the focus and asks the window manager to make the
 * shell active.
 *
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see Control#moveAbove
 * @see Control#setFocus
 * @see Control#setVisible
 * @see Display#getActiveShell
 * @see Decorations#setDefaultButton
 * @see Shell#setActive
 * @see Shell#forceActive
 */
public void open () {
	checkWidget ();
	bringToTop ();
	/*
	* Feature on WinCE PPC.  A new application becomes
	* the foreground application only if it has at least
	* one visible window before the event loop is started.
	* The workaround is to explicitely force the shell to
	* be the foreground window.
	*/
	version(WinCE) { OS.SetForegroundWindow (handle); }
	OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
	setVisible (true);
	/*
	* Bug in Windows XP.  Despite the fact that an icon has been
	* set for a window, the task bar displays the wrong icon the
	* first time the window is made visible with ShowWindow() after
	* a call to BringToTop(), when a long time elapses between the
	* ShowWindow() and the time the event queue is read.  The icon
	* in the window trimming is correct but the one in the task
	* bar does not get updated.  The fix is to call PeekMessage()
	* with the flag PM_NOREMOVE and PM_QS_SENDMESSAGE to respond
	* to a cross thread WM_GETICON.
	* 
	* NOTE: This allows other cross thread messages to be delivered,
	* most notably WM_ACTIVATE.
	*/
	MSG* msg = new MSG ();
	int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_SENDMESSAGE;
	OS.PeekMessage (msg, null, 0, 0, flags);
	if (!restoreFocus ()) traverseGroup (true);
}

void releaseChild () {
	/* Do nothing */
}

void releaseHandle () {
	super.releaseHandle ();
	hwndMDIClient_var = null;
}

void releaseShells () {
	Shell [] shells = getShells ();
	for (int i=0; i<shells.length; i++) {
		Shell shell = shells [i];
		if (!shell.isDisposed ()) shell.releaseResources ();
	}
}

void releaseWidget () {
	releaseShells ();
	super.releaseWidget ();
	activeMenu = null;
	display.clearModal (this);
	toolTipHandle = null;
	if (brushes !is null) {
		for (int i=0; i<brushes.length; i++) {
			HBRUSH hBrush = brushes [i];
			if (hBrush !is null) OS.DeleteObject (hBrush);
		}
	}
	brushes = null;
	if (OS.IsDBLocale) {
		if (hIMC !is null) OS.ImmDestroyContext (hIMC);
	}
	lastActive = null;
	region = null;
}

void removeMenu (Menu menu) {
	super.removeMenu (menu);
	if (menu is activeMenu) activeMenu = null;
}

/**
 * Removes the listener from the collection of listeners who will
 * be notified when operations are performed on the receiver.
 *
 * @param listener the listener which should no longer be notified
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
 * </ul>
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see ShellListener
 * @see #addShellListener
 */
public void removeShellListener (ShellListener listener) {
	checkWidget ();
	if (listener is null) error(__FILE__, __LINE__, DWT.ERROR_NULL_ARGUMENT);
	if (eventTable is null) return;
	eventTable.unhook (DWT.Close, listener);
	eventTable.unhook (DWT.Iconify,listener);
	eventTable.unhook (DWT.Deiconify,listener);
	eventTable.unhook (DWT.Activate, listener);
	eventTable.unhook (DWT.Deactivate, listener);
}

LDWTRESULT selectPalette (HPALETTE hPalette) {
	HDC hDC = OS.GetDC (handle);
	HGDIOBJ hOld = OS.SelectPalette (hDC, hPalette, false);
	int result = OS.RealizePalette (hDC);
	if (result > 0) {
		OS.InvalidateRect (handle, null, true);
	} else {
		OS.SelectPalette (hDC, hOld, true);
		OS.RealizePalette (hDC);
	}
	OS.ReleaseDC (handle, hDC);
	return (result > 0) ? LDWTRESULT.ONE : LDWTRESULT.ZERO;
}

/**
 * Moves the receiver to the top of the drawing order for
 * the display on which it was created (so that all other
 * shells on that display, which are not the receiver's
 * children will be drawn behind it) and asks the window
 * manager to make the shell active.
 *
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @since 2.0
 * @see Control#moveAbove
 * @see Control#setFocus
 * @see Control#setVisible
 * @see Display#getActiveShell
 * @see Decorations#setDefaultButton
 * @see Shell#open
 * @see Shell#setActive
 */
public void setActive () {
	checkWidget ();
	bringToTop ();
}

void setActiveControl (Control control) {
	if (control !is null && control.isDisposed ()) control = null;
	if (lastActive !is null && lastActive.isDisposed ()) lastActive = null;
	if (lastActive is control) return;
	
	/*
	* Compute the list of controls to be activated and
	* deactivated by finding the first common parent
	* control.
	*/
	Control [] activate = (control is null) ? new Control [0] : control.getPath ();
	Control [] deactivate = (lastActive is null) ? new Control [0] : lastActive.getPath ();
	lastActive = control;
	int index = 0, length = Math.min (activate.length, deactivate.length);
	while (index < length) {
		if (activate [index] !is deactivate [index]) break;
		index++;
	}
	
	/*
	* It is possible (but unlikely), that application
	* code could have destroyed some of the widgets. If
	* this happens, keep processing those widgets that
	* are not disposed.
	*/
	for (int i=deactivate.length-1; i>=index; --i) {
		if (!deactivate [i].isDisposed ()) {
			deactivate [i].sendEvent (DWT.Deactivate);
		}
	}
	for (int i=activate.length-1; i>=index; --i) {
		if (!activate [i].isDisposed ()) {
			activate [i].sendEvent (DWT.Activate);
		}
	}
}

void setBounds5 (int x, int y, int width, int height, int flags) {
	version(WinCE) {
		swFlags = OS.SW_RESTORE;
	} else {
		if (OS.IsIconic (handle) || OS.IsZoomed (handle)) {
			setPlacement (x, y, width, height, flags);
			return;
		}
	}
	SetWindowPos (handle, null, x, y, width, height, flags);
}

public void setEnabled (boolean enabled) {
	checkWidget ();
	if (((state & DISABLED) == 0) == enabled) return;
	super.setEnabled (enabled);
	if (enabled && handle is OS.GetActiveWindow ()) {
		if (!restoreFocus ()) traverseGroup (true);
	}
}

/**
 * Sets the input method editor mode to the argument which 
 * should be the result of bitwise OR'ing together one or more
 * of the following constants defined in class <code>DWT</code>:
 * <code>NONE</code>, <code>ROMAN</code>, <code>DBCS</code>, 
 * <code>PHONETIC</code>, <code>NATIVE</code>, <code>ALPHA</code>.
 *
 * @param mode the new IME mode
 *
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @see DWT
 */
public void setImeInputMode (int mode) {
	checkWidget ();
	if (!OS.IsDBLocale) return;
	boolean imeOn = mode != DWT.NONE && mode != DWT.ROMAN;
	HIMC hIMC = OS.ImmGetContext (handle);
	OS.ImmSetOpenStatus (hIMC, imeOn);
	if (imeOn) {
		DWORD lpfdwConversion;
		DWORD lpfdwSentence;
		if (OS.ImmGetConversionStatus (hIMC, &lpfdwConversion, &lpfdwSentence)) {
			int newBits = 0;
			int oldBits = OS.IME_CMODE_NATIVE | OS.IME_CMODE_KATAKANA;
			if ((mode & DWT.PHONETIC) != 0) {
				newBits = OS.IME_CMODE_KATAKANA | OS.IME_CMODE_NATIVE;
				oldBits = 0;
			} else {
				if ((mode & DWT.NATIVE) != 0) {
					newBits = OS.IME_CMODE_NATIVE;
					oldBits = OS.IME_CMODE_KATAKANA;
				}
			}
			if ((mode & DWT.DBCS) != 0) {
				newBits |= OS.IME_CMODE_FULLSHAPE;
			} else {
				oldBits |= OS.IME_CMODE_FULLSHAPE;
			}
			if ((mode & DWT.ROMAN) != 0) {
				newBits |= OS.IME_CMODE_ROMAN;
			} else {
				oldBits |= OS.IME_CMODE_ROMAN;
			}
			lpfdwConversion |= newBits;  lpfdwConversion &= ~oldBits;
			OS.ImmSetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence);
		}
	}
	OS.ImmReleaseContext (handle, hIMC);
}

void setItemEnabled (int cmd, boolean enabled) {
	HMENU hMenu = OS.GetSystemMenu (handle, false);
	if (hMenu is null) return;
	int flags = OS.MF_ENABLED;
	if (!enabled) flags = OS.MF_DISABLED | OS.MF_GRAYED;
	OS.EnableMenuItem (hMenu, cmd, OS.MF_BYCOMMAND | flags);
}

/**
 * Sets the receiver's minimum size to the size specified by the arguments.
 * If the new minimum size is larger than the current size of the receiver,
 * the receiver is resized to the new minimum size.
 *
 * @param width the new minimum width for the receiver
 * @param height the new minimum height for the receiver
 *
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 * 
 * @since 3.1
 */
public void setMinimumSize (int width, int height) {
	checkWidget ();
	int widthLimit = 0, heightLimit = 0;
	int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX;
	if ((style & DWT.NO_TRIM) == 0 && (style & trim) != 0) {
		widthLimit = OS.GetSystemMetrics (OS.SM_CXMINTRACK);
		if ((style & DWT.RESIZE) != 0) {
			heightLimit = OS.GetSystemMetrics (OS.SM_CYMINTRACK);
		} else {
			RECT rect;
			int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
			int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
			OS.AdjustWindowRectEx (&rect, bits1, false, bits2);
			heightLimit = rect.bottom - rect.top;
		}
	} 
	minWidth = Math.max (widthLimit, width);
	minHeight = Math.max (heightLimit, height);
	Point size = getSize ();
	int newWidth = Math.max (size.x, minWidth);
	int newHeight = Math.max (size.y, minHeight);
	if (minWidth <= widthLimit) minWidth = DWT.DEFAULT;
	if (minHeight <= heightLimit) minHeight = DWT.DEFAULT;
	if (newWidth != size.x || newHeight != size.y) setSize (newWidth, newHeight);
}

/**
 * Sets the receiver's minimum size to the size specified by the argument.
 * If the new minimum size is larger than the current size of the receiver,
 * the receiver is resized to the new minimum size.
 *
 * @param size the new minimum size for the receiver
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
 * </ul>
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 * 
 * @since 3.1
 */
public void setMinimumSize (Point size) {
	assert(size);
	checkWidget ();
	setMinimumSize (size.x, size.y);
}


void setParent () {
	/* Do nothing.  Not necessary for Shells */
}

/**
 * Sets the shape of the shell to the region specified
 * by the argument.  When the argument is null, the
 * default shape of the shell is restored.  The shell
 * must be created with the style DWT.NO_TRIM in order
 * to specify a region.
 *
 * @param region the region that defines the shape of the shell (or null)
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
 * </ul>  
 * @exception SWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 * </ul>
 *
 * @since 3.0
 *
 */
public void setRegion (Region region) {
	checkWidget ();
	if ((style & DWT.NO_TRIM) == 0) return;
	if (region !is null && region.isDisposed()) error(__FILE__, __LINE__, DWT.ERROR_INVALID_ARGUMENT);
	HRGN hRegion = null;
	if (region !is null) {
		hRegion = OS.CreateRectRgn (0, 0, 0, 0);
		OS.CombineRgn (hRegion, region.handle, hRegion, OS.RGN_OR);
	}
	OS.SetWindowRgn (handle, hRegion, true);
	this.region = region;
}

void setToolTipText (HWND hwnd, char[] text) {
	version(WinCE){	
		return;
	}
	else
	{
		if (toolTipHandle is null) {
			toolTipHandle = OS.CreateWindowEx (
				0,
				Converter.StrToTCHARz(OS.TOOLTIPS_CLASS),
				null,
				OS.TTS_ALWAYSTIP,
				OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
				handle,
				null,
				OS.GetModuleHandle (null),
				null);
			if (toolTipHandle is null) {
				error(__FILE__, __LINE__, DWT.ERROR_NO_HANDLES);	
				return;
			}
			/*
			* Feature in Windows.  Despite the fact that the
			* tool tip text contains \r\n, the tooltip will
			* not honour the new line unless TTM_SETMAXTIPWIDTH
			* is set.  The fix is to set TTM_SETMAXTIPWIDTH to
			* a large value.
			*/
			OS.SendMessage (toolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
		}
		TOOLINFO lpti;
		lpti.cbSize = TOOLINFO.sizeof;
		lpti.uId = cast(UINT)hwnd;
		lpti.hwnd = handle;
		if (text is null) {
			OS.SendMessage (toolTipHandle, OS.TTM_DELTOOL, 0,  &lpti);
		} else {
			lpti.uFlags = OS.TTF_IDISHWND | OS.TTF_SUBCLASS;
			lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
			OS.SendMessage (toolTipHandle, OS.TTM_ADDTOOL, 0,  &lpti);
		}
		OS.SendMessage (toolTipHandle, OS.TTM_UPDATE, 0, 0);
	}
}

// <Shawn> do this directly in Composite.WM_NOTIFY_(...)
//void setToolTipText (NMTTDISPINFO* lpnmtdi, TCHAR [] buffer) {
	/*
	* Ensure that the current position of the mouse
	* is inside the client area of the shell.  This
	* prevents tool tips from popping up over the
	* shell trimmings.
	*/

	// <Shawn>: DWT doesn't need this at all
	// see Composite.WM_NOTIFY (int wParam, int lParam)
	
/*	if (!hasCursor ()) return;
	if(buffer)
		lpnmtdi.lpszText = cast(TCHAR*)buffer;
*/		
//}

public void setVisible (boolean visible) {
	checkWidget ();
	if (drawCount != 0) {
		if (((state & HIDDEN) == 0) == visible) return;
	} else {
		if (visible == OS.IsWindowVisible (handle)) return;
	}
	
	/*
	* Feature in Windows.  When ShowWindow() is called used to hide
	* a window, Windows attempts to give focus to the parent. If the
	* parent is disabled by EnableWindow(), focus is assigned to
	* another windows on the desktop.  This means that if you hide
	* a modal window before the parent is enabled, the parent will
	* not come to the front.  The fix is to change the modal state
	* before hiding or showing a window so that this does not occur.
	*/
	int mask = DWT.PRIMARY_MODAL | DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL;
	if ((style & mask) != 0) {
		if (visible) {
			display.setModalShell (this);
			Control control = display.getFocusControl ();
			if (control !is null && !control.isActive ()) bringToTop ();
			HWND hwndShell = OS.GetActiveWindow ();
			if (hwndShell is null) {
				if (parent !is null) hwndShell = parent.handle;
			}
			if (hwndShell !is null) {
				OS.SendMessage (hwndShell, OS.WM_CANCELMODE, 0, 0);
			}
			OS.ReleaseCapture ();
		} else {
			display.clearModal (this);
		}
	} else {
		updateModal ();
	}
	
	/*
	* Bug in Windows.  Calling ShowOwnedPopups() to hide the
	* child windows of a hidden window causes the application
	* to be deactivated.  The fix is to call ShowOwnedPopups()
	* to hide children before hiding the parent.
	*/
	if (showWithParent && !visible) {
		version(WinCE) {} else {  OS.ShowOwnedPopups (handle, false); }
	}
	super.setVisible (visible);
	if (isDisposed ()) return;
	if (showWithParent == visible) return;
	showWithParent = visible;
	if (visible) {
		version(WinCE) {} else {  OS.ShowOwnedPopups (handle, true); }
	}
}

boolean translateAccelerator (MSG* msg) {
	if (!isEnabled () || !isActive ()) return false;
	if (menuBar !is null && !menuBar.isEnabled ()) return false;
	return translateMDIAccelerator (msg) || translateMenuAccelerator (msg);
}

boolean traverseEscape () {
	if (parent is null) return false;
	if (!isVisible () || !isEnabled ()) return false;
	close ();
	return true;
}

void updateModal () {
	if (Display.TrimEnabled) {
		setItemEnabled (OS.SC_CLOSE, isActive ());
	} else {
		OS.EnableWindow (handle, isActive ());
	}
}

CREATESTRUCT* widgetCreateStruct () {
	return null;
}

HWND widgetParent () {
	if (handle !is null) return handle;
	return parent !is null ? parent.handle : null;
}

int widgetExtStyle () {
	int bits = super.widgetExtStyle () & ~OS.WS_EX_MDICHILD;

	/*
	* Feature in Windows.  When a window that does not have a parent
	* is created, it is automatically added to the Windows Task Bar,
	* even when it has no title.  The fix is to use WS_EX_TOOLWINDOW
	* which does not cause the window to appear in the Task Bar.
	*/
	version(WinCE) { } else {
		if (parent is null) {
			if ((style & DWT.ON_TOP) != 0) {
				int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX;
				if ((style & DWT.NO_TRIM) != 0 || (style & trim) == 0) {
					bits |= OS.WS_EX_TOOLWINDOW;
				}
			}
		}
	}
			
	/*
	* Bug in Windows 98 and NT.  Creating a window with the
	* WS_EX_TOPMOST extended style can result in a dialog shell
	* being moved behind its parent.  The exact case where this
	* happens is a shell with two dialog shell children where
	* each dialog child has another hidden dialog child with
	* the WS_EX_TOPMOST extended style.  Clicking on either of
	* the visible dialogs causes them to become active but move
	* to the back, behind the parent shell.  The fix is to
	* disallow the WS_EX_TOPMOST extended style on Windows 98
	* and NT.
	*/
	if (parent !is null) {
		if (OS.IsWin95) return bits;
		if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) {
			return bits;
		}
	}
	if ((style & DWT.ON_TOP) != 0) bits |= OS.WS_EX_TOPMOST;
	return bits;
}

char[] windowClass() {
	if (OS.IsSP) return DialogClass;
	return parent !is null ? DialogClass : super.windowClass ();
}

WNDPROC_I windowProc2 () {
	if (OS.IsSP) return DialogProc;
	return parent !is null ? DialogProc : super.windowProc2 ();
}

int widgetStyle () {
	int bits = super.widgetStyle ();
	if (handle !is null) return bits | OS.WS_CHILD;
	bits &= ~OS.WS_CHILD;
	/*
	* Feature in WinCE.  Calling CreateWindowEx () with WS_OVERLAPPED
	* and a parent window causes the new window to become a WS_CHILD of
	* the parent instead of a dialog child.  The fix is to use WS_POPUP
	* for a window with a parent.  
	* 
	* Feature in WinCE PPC.  A window without a parent with WS_POPUP
	* always shows on top of the Pocket PC 'Today Screen'. The fix
	* is to not set WS_POPUP for a window without a parent on WinCE
	* devices.
	* 
	* NOTE: WS_POPUP causes CreateWindowEx () to ignore CW_USEDEFAULT
	* and causes the default window location and size to be zero.
	*/
	version(WinCE) {
		if (OS.IsSP) return bits | OS.WS_POPUP;
		return parent is null ? bits : bits | OS.WS_POPUP;
	}
	
	/*
	* Use WS_OVERLAPPED for all windows, either dialog or top level
	* so that CreateWindowEx () will respect CW_USEDEFAULT and set
	* the default window location and size.
	* 
	* NOTE:  When a WS_OVERLAPPED window is created, Windows gives
	* the new window WS_CAPTION style bits.  These two constants are
	* as follows:
	* 
	* 	WS_OVERLAPPED = 0
	* 	WS_CAPTION = WS_BORDER | WS_DLGFRAME
	* 
	*/
	return bits | OS.WS_OVERLAPPED | OS.WS_CAPTION;
}

LDWTRESULT WM_ACTIVATE_ (int wParam, int lParam) {
	version(WinCE)
	{
		if (OS.IsPPC) {
			/*
			* Note: this does not work when we get WM_ACTIVATE prior
			* to adding a listener.
			*/
			if (hooks (DWT.HardKeyDown) || hooks (DWT.HardKeyUp)) {
				int fActive = wParam & 0xFFFF;
				HWND hwnd = fActive != 0 ? handle : 0;
				for (int bVk=OS.VK_APP1; bVk<=OS.VK_APP6; bVk++) {
					OS.SHSetAppKeyWndAssoc (cast(byte) bVk, hwnd);
				}
			}
			/* Restore SIP state when window is activated */
			if ((wParam & 0xFFFF) != 0) {
				OS.SHSipPreference (handle, psai.fSipUp == 0 ? OS.SIP_DOWN : OS.SIP_UP);
			} 
		}
	}

	/*
	* Bug in Windows XP.  When a Shell is deactivated, the
	* IME composition window does not go away. This causes
	* repaint issues.  The fix is to close the IME ourselves
	* when the Shell is deactivated.
	* 
	* Note.  When the Shell is reactivated, the text in the
	* composition window has been lost.
	*/
	if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) >= (5 << 16 | 1)) {
		if ((wParam & 0xFFFF) == 0 && OS.IsDBLocale && hIMC !is null) {
			OS.ImmSetOpenStatus (hIMC, false);
		}
	}
	
	LDWTRESULT result = super.WM_ACTIVATE_ (wParam, lParam);
	if (parent !is null) return LDWTRESULT.ZERO;
	return result;
}

LDWTRESULT WM_COMMAND_ (int wParam, int lParam) {
	version(WinCE)
	{
	if (OS.IsPPC) {
		/*
		* Note in WinCE PPC:  Close the Shell when the "Done Button" has
		* been pressed. lParam is either 0 (PocketPC 2002) or the handle
		* to the Shell (PocketPC).
		*/
		int loWord = wParam & 0xFFFF;
		if (loWord == OS.IDOK && (lParam == 0 || lParam == cast(int)handle)) {
			OS.PostMessage (handle, OS.WM_CLOSE, 0, 0);
			return LDWTRESULT.ZERO;			
		}
	}
	/*
	* Feature in Windows.  On PPC, the menu is not actually an HMENU.
	* By observation, it is a tool bar that is configured to look like
	* a menu.  Therefore, when the PPC menu sends WM_COMMAND messages,
	* lParam is not zero because the WM_COMMAND was not sent from a menu.
	* Sub menu item events originate from the menu bar.  Top menu items
	* events originate from a tool bar.  The fix is to detect the source
	* of the WM_COMMAND and set lParam to zero to pretend that the message
	* came from a real Windows menu, not a tool bar.
	*/
	if (OS.IsPPC || OS.IsSP) {
		if (menuBar !is null) {
			HWND hwndCB = menuBar.hwndCB;
			if (lParam != 0 && hwndCB !is null) {
				if (lParam == hwndCB) {
					return super.WM_COMMAND_ (wParam, 0);
				} else {
					HWND hwndChild = OS.GetWindow (hwndCB, OS.GW_CHILD);
					if (lParam == hwndChild) return super.WM_COMMAND_ (wParam, 0);					
				}
			}
		}
	}
	}
	return super.WM_COMMAND_ (wParam, lParam);
}

LDWTRESULT WM_DESTROY_ (int wParam, int lParam) {
	LDWTRESULT result = super.WM_DESTROY_ (wParam, lParam);
	/*
	* When the shell is a WS_CHILD window of a non-DWT
	* window, the destroy code does not get called because
	* the non-DWT window does not call dispose ().  Instead,
	* the destroy code is called here in WM_DESTROY.
	*/
	int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
	if ((bits & OS.WS_CHILD) != 0) {
		releaseChild ();
		releaseResources ();
	}
	return result;
}

LDWTRESULT WM_ENTERIDLE_ (int wParam, int lParam) {
	LDWTRESULT result = super.WM_ENTERIDLE_ (wParam, lParam);
	if (result !is null) return result;
	if (display.runAsyncMessages ()) display.wakeThread ();
	return result;
}

LDWTRESULT WM_GETMINMAXINFO_ (int wParam, int lParam) {
	LDWTRESULT result = super.WM_GETMINMAXINFO_ (wParam, lParam);
	if (result !is null) return result;
	if (minWidth != DWT.DEFAULT || minHeight != DWT.DEFAULT) {
		MINMAXINFO* info = cast(MINMAXINFO*)lParam;
		if (minWidth != DWT.DEFAULT) info.ptMinTrackSize.x = minWidth;
		if (minHeight != DWT.DEFAULT) info.ptMinTrackSize.y = minHeight;
		return LDWTRESULT.ZERO;
	}
	return result;
}

LDWTRESULT WM_MOUSEACTIVATE_ (int wParam, int lParam) {
	LDWTRESULT result = super.WM_MOUSEACTIVATE_ (wParam, lParam);
	if (result !is null) return result;
	
	/*
	* Check for WM_MOUSEACTIVATE when an MDI shell is active
	* and stop the normal shell activation but allow the mouse
	* down to be delivered.
	*/
	int hittest = cast(short) (lParam & 0xFFFF);
	switch (hittest) {
		case OS.HTERROR:
		case OS.HTTRANSPARENT:
		case OS.HTNOWHERE:
			break;
		default: {
			Control control = display.getFocusControl ();
			if (control !is null) {
				Decorations decorations = control.menuShell ();
				if (decorations.getShell () is this && decorations !is this) {
					display.ignoreRestoreFocus = true;
					display.lastHittest = hittest;
					display.lastHittestControl = null;
					if (hittest == OS.HTMENU || hittest == OS.HTSYSMENU) {
						display.lastHittestControl = control;
						return null;
					}
					if (OS.IsWin95 && hittest == OS.HTCAPTION) {
						display.lastHittestControl = control;
					}
					return new LDWTRESULT (OS.MA_NOACTIVATE);
				}
			}
		}
	}
	if (hittest == OS.HTMENU) return null;
	
	/*
	* Get the current location of the cursor,
	* not the location of the cursor when the
	* WM_MOUSEACTIVATE was generated.  This is
	* strictly incorrect but is necessary in
	* order to support Activate and Deactivate
	* events for embedded widgets that have
	* their own event loop.  In that case, the
	* cursor location reported by GetMessagePos
	* is the one for our event loop, not the
	* embedded widget's event loop.
	*/
	POINT pt;
	if (!OS.GetCursorPos (&pt)) {
		int pos = OS.GetMessagePos ();
		pt.x = cast(short) (pos & 0xFFFF);
		pt.y = cast(short) (pos >> 16);
	}
	HWND hwnd = OS.WindowFromPoint (pt);
	if (hwnd is null) return null;
	Control control = display.findControl (hwnd);
	setActiveControl (control);
	
	/*
	* This code is intentionally commented.  On some platforms,
	* shells that are created with DWT.NO_TRIM won't take focus
	* when the user clicks in the client area or on the border.
	* This behavior is usedful when emulating tool tip shells
	* Until this behavior is specified, this code will remain
	* commented.
	*/
//	if ((style & DWT.NO_TRIM) != 0) {
//		if (hittest == OS.HTBORDER || hittest == OS.HTCLIENT) {
//			return new LRESULT (OS.MA_NOACTIVATE);
//		}
//	}
	return null;
}

LDWTRESULT WM_NCHITTEST_ (int wParam, int lParam) {
	if (!OS.IsWindowEnabled (handle)) return null;
	if (!isEnabled () || !isActive ()) {
		if (!Display.TrimEnabled) return new LDWTRESULT (OS.HTNOWHERE);
		int hittest = callWindowProc (OS.WM_NCHITTEST, wParam, lParam);
		if (hittest == OS.HTCLIENT || hittest == OS.HTMENU) hittest = OS.HTBORDER;
		return new LDWTRESULT (hittest);
	}
	if (menuBar !is null && !menuBar.getEnabled ()) {
		int hittest = callWindowProc (OS.WM_NCHITTEST, wParam, lParam);
		if (hittest == OS.HTMENU) hittest = OS.HTBORDER;
		return new LDWTRESULT (hittest);
	}
	return null;
}

LDWTRESULT WM_NCLBUTTONDOWN_ (int wParam, int lParam) {
	LDWTRESULT result = super.WM_NCLBUTTONDOWN_ (wParam, lParam);
	if (result !is null) return result;
	/*
	* When the normal activation was interruped in WM_MOUSEACTIVATE
	* because the active shell was an MDI shell, set the active window
	* to the top level shell but lock the active window and stop focus
	* changes.  This allows the user to interact the top level shell
	* in the normal manner.
	*/
	if (!display.ignoreRestoreFocus) return result;
	Display display = this.display;
	HWND hwndActive = null;
	boolean fixActive = OS.IsWin95 && display.lastHittest == OS.HTCAPTION;
	if (fixActive) hwndActive = OS.SetActiveWindow (handle);
	display.lockActiveWindow = true;
	int code = callWindowProc (OS.WM_NCLBUTTONDOWN, wParam, lParam);
	display.lockActiveWindow = false;
	if (fixActive) OS.SetActiveWindow (hwndActive);
	Control focusControl = display.lastHittestControl;
	if (focusControl !is null && !focusControl.isDisposed ()) {
		focusControl.setFocus ();
	}
	display.lastHittestControl = null;
	display.ignoreRestoreFocus = false;
	return new LDWTRESULT (code);
}

LDWTRESULT WM_PALETTECHANGED_ (int wParam, int lParam) {
	if (wParam != cast(int)handle) {
		HPALETTE hPalette = display.hPalette;
		if (hPalette !is null) return selectPalette (hPalette);
	}
	return super.WM_PALETTECHANGED_ (wParam, lParam);
}

LDWTRESULT WM_QUERYNEWPALETTE_ (int wParam, int lParam) {
	HPALETTE hPalette = display.hPalette;
	if (hPalette !is null) return selectPalette (hPalette);
	return super.WM_QUERYNEWPALETTE_ (wParam, lParam);
}

LDWTRESULT WM_SETCURSOR_ (int wParam, int lParam) {
	/*
	* Feature in Windows.  When the shell is disabled
	* by a Windows standard dialog (like a MessageBox
	* or FileDialog), clicking in the shell does not
	* bring the shell or the dialog to the front. The
	* fix is to detect this case and bring the shell
	* forward.
	*/
	int msg = cast(short) (lParam >> 16);
	if (msg == OS.WM_LBUTTONDOWN) {
		if (!Display.TrimEnabled) {
			Shell modalShell = display.getModalShell ();
			if (modalShell !is null && !isActive ()) {
				HWND hwndModal = modalShell.handle;
				if (OS.IsWindowEnabled (hwndModal)) {
					OS.SetActiveWindow (hwndModal);
				}
			}
		}
		if (!OS.IsWindowEnabled (handle)) {
			version(WinCE) { } else {
				HWND hwndPopup = OS.GetLastActivePopup (handle);
				if (hwndPopup !is null && hwndPopup !is handle) {
					if (display.getControl (hwndPopup) is null) {
						if (OS.IsWindowEnabled (hwndPopup)) {
							OS.SetActiveWindow (hwndPopup);
						}
					}
				}
			}
		}
	}
	/*
	* When the shell that contains a cursor is disabled,
	* WM_SETCURSOR is called with HTERROR.  Normally,
	* when a control is disabled, the parent will get
	* mouse and cursor events.  In the case of a disabled
	* shell, there is no enabled parent.  In order to
	* show the cursor when a shell is disabled, it is
	* necessary to override WM_SETCURSOR when called
	* with HTERROR to set the cursor but only when the
	* mouse is in the client area of the shell.
	*/
	int hitTest = cast(short) (lParam & 0xFFFF);
	if (hitTest == OS.HTERROR) {
		if (!getEnabled ()) {
			Control control = display.getControl (cast(HWND)wParam);
			if (control is this && cursor !is null) {
				POINT pt;
				if (OS.GetCursorPos (&pt)) {
					OS.ScreenToClient (handle, &pt);
					RECT rect;
					OS.GetClientRect (handle, &rect);
					if (OS.PtInRect (&rect, pt)) {
						OS.SetCursor (cursor.handle);
						switch (msg) {
							case OS.WM_LBUTTONDOWN:
							case OS.WM_RBUTTONDOWN:
							case OS.WM_MBUTTONDOWN:
								OS.MessageBeep (OS.MB_OK);
							default : break;
						}
						return LDWTRESULT.ONE;
					}
				}
			}
		}
	}
	return super.WM_SETCURSOR_ (wParam, lParam);
}

LDWTRESULT WM_SETTINGCHANGE_ (int wParam, int lParam) {
	LDWTRESULT result = super.WM_SETTINGCHANGE_ (wParam, lParam);
	if (result !is null) return result;
	version(WinCE)
	{
		if (OS.IsPPC) {
			if (wParam == OS.SPI_SETSIPINFO) {
				/* 
				* The SIP is in a new state.  Cache its new value.
				* Resize the Shell if it has the style DWT.RESIZE.
				* Note that SHHandleWMSettingChange resizes the
				* Shell and also updates the cached state.
				*/
				if ((style & DWT.RESIZE) != 0) {
					OS.SHHandleWMSettingChange (handle, wParam, lParam, psai);
					return LDWTRESULT.ZERO;
				} else {
					SIPINFO pSipInfo;
					pSipInfo.cbSize = SIPINFO.sizeof;
					OS.SipGetInfo (&pSipInfo);
					psai.fSipUp = pSipInfo.fdwFlags & OS.SIPF_ON;					
				}
			}
		}
	}
	return result;
}

LDWTRESULT WM_SHOWWINDOW_ (int wParam, int lParam) {
	LDWTRESULT result = super.WM_SHOWWINDOW_ (wParam, lParam);
	if (result !is null) return result;
	/*
	* Bug in Windows.  If the shell is hidden while the parent
	* is iconic,  Windows shows the shell when the parent is
	* deiconified.  This does not happen if the shell is hidden
	* while the parent is not an icon.  The fix is to track
	* visible state for the shell and refuse to show the shell
	* when the parent is shown.
	*/
	if (lParam == OS.SW_PARENTOPENING) {
		Control control = this;
		while (control !is null) {
			Shell shell = control.getShell ();
			if (!shell.showWithParent) return LDWTRESULT.ZERO;
			control = control.parent;
		}
	}
	return result;
}


LDWTRESULT WM_WINDOWPOSCHANGING_ (int wParam, int lParam) {
	LDWTRESULT result = super.WM_WINDOWPOSCHANGING_ (wParam,lParam);
	if (result !is null) return result;
	WINDOWPOS* lpwp = cast(WINDOWPOS*)lParam;
//	OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
	if ((lpwp.flags & OS.SWP_NOSIZE) == 0) {
		lpwp.cx = Math.max (lpwp.cx, minWidth);
		int trim = DWT.TITLE | DWT.CLOSE | DWT.MIN | DWT.MAX;
		if ((style & DWT.NO_TRIM) == 0 && (style & trim) != 0) {
			lpwp.cx = Math.max (lpwp.cx, OS.GetSystemMetrics (OS.SM_CXMINTRACK));
		}
		lpwp.cy = Math.max (lpwp.cy, minHeight);
		if ((style & DWT.NO_TRIM) == 0 && (style & trim) != 0) {
			if ((style & DWT.RESIZE) != 0) {
				lpwp.cy = Math.max (lpwp.cy, OS.GetSystemMetrics (OS.SM_CYMINTRACK));
			} else {
				RECT rect;
				int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
				int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
				OS.AdjustWindowRectEx (&rect, bits1, false, bits2);
				lpwp.cy = Math.max (lpwp.cy, rect.bottom - rect.top);
			}
		}
//		OS.MoveMemory (lParam, lpwp, WINDOWPOS.sizeof);
	}
	return result;
}


// Shell Event Handler
public void handleShellClose(Object customData, void delegate(ShellEvent) func){
	handleEvent(new ShellHandler(customData, DWT.Close, func));
}
public void handleShellIconify(Object customData, void delegate(ShellEvent) func){
	handleEvent(new ShellHandler(customData, DWT.Iconify, func));
}
public void handleShellDeiconify(Object customData, void delegate(ShellEvent) func){
	handleEvent(new ShellHandler(customData, DWT.Deiconify, func));
}
public void handleShellActivate(Object customData, void delegate(ShellEvent) func){
	handleEvent(new ShellHandler(customData, DWT.Activate, func));
}
public void handleShellDeactivate(Object customData, void delegate(ShellEvent) func){
	handleEvent(new ShellHandler(customData, DWT.Deactivate, func));
}

}
